/*
 *
 *  Copyright (C) 2009 GSyC/LibreSoft
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see http://www.gnu.org/licenses/. 
 *
 *  Authors : Roberto Calvo Palomino <rocapal@gsyc.es>
 *  		  Juan Francisco Gato Luis <jfcogato@gsyc.es>
 *
 */

package com.sitem.appsjam.Managers;

import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.os.AsyncTask;
import android.util.Log;

import com.sitem.appsjam.Managers.LocManager.OnLocationUpdateListener;
import com.sitem.appsjam.Types.Layer;
import com.sitem.appsjam.Types.Punt;
import com.sitem.appsjam.Utils.Utils;

public class LayerManager {
	
	private static ArrayList<Layer> layerList = new ArrayList<Layer>();
	public static OnRefreshFinished listener;
	private static boolean running = false;
	
	public interface OnRefreshFinished {
		public abstract void onFinish(boolean success);
	}

	public static boolean isRunning() {
		return running;
	}

	public static void init(Activity activity) {
		LocManager.addLocationListener(new OnLocationUpdateListener() {
			public void onUpdate(Location loc) {
				if (loc != null) {
					LayerManager.refreshLayers(); //Necessita que el LocationManager estigui iniciat
					LocManager.removeLocationListener(this);
				}
			}
		});
	}
	
	public static void refreshLayers() {
		layerList = new ArrayList<Layer>();
		new AsyncTask<Void, Void, ArrayList<Layer>>() {
			protected void onPostExecute(ArrayList<Layer> list) {
				running = false;
				if (list == null) {
					Log.i("LayerManager","Error!");
					if(listener != null) listener.onFinish(false);
				} else {  
					layerList = list;
					if(listener != null) listener.onFinish(true);
				}
			}    
			@Override
			protected ArrayList<Layer> doInBackground(Void... unused){
				running = true;
				try {
					DefaultHttpClient httpclient = new DefaultHttpClient();
					String url = "http://www.gooltracking.com/appsjam/getData";
					Log.i("LayerManager","Demanant punts");
					Log.i("LayerManager",url);
					HttpPost httpost = new HttpPost(url);
					HttpResponse response = httpclient.execute(httpost);
					HttpEntity entity = response.getEntity(); 
			        String s = Utils.convertStreamToString(entity.getContent());
			        return parseLayerList(s);
				} catch(Exception e) {
					Log.e("LayerManager", "", e);
				}
				return null;
			}

		}.execute();
	}
	
	public static int getNumLayers() {
		return layerList.size();
	}
	public static Layer getLayer(int num) {
		return layerList.get(num);
	}
	public static ArrayList<Layer> getAllLayers() {
		return layerList;
	}

	public static ArrayList<Punt> getVisibleNodes() {
		ArrayList<Punt> list = new ArrayList<Punt>();
		for (Layer layer : layerList) {
			if (layer.visible) list.addAll(layer.nodes);
		}
		Log.i("LayerManager", list.size() + " nodes visibles.");
		return list;
	}
		
	private static ArrayList<Layer> parseLayerList (String str)	{
        ArrayList<Layer> list = new ArrayList<Layer>();
        try {
        	JSONObject obj = new JSONObject(str);
        	Iterator<String> keys = obj.keys();
        	while(keys.hasNext()) {
        		String s = keys.next();
        		//Log.e("s",s);
				Layer l = parseLayer(obj.getJSONObject(s));
				if (l != null) list.add(l);        		
        	}
/*
        	JSONArray array = obj.toJSONArray(names)
        	//JSONArray array = new JSONArray(str);
			for (int i = 0; i < array.length(); i++) { 
				Layer l = parseLayer(array.getJSONObject(i));
				if (l != null) list.add(l);
			}
			*/
			Log.i("ParseLayerList", "Llegides " + list.size() + " capes.");
			return list;
		} catch (JSONException e) {	
			Log.e("ParseNodes","S'esperava un array de capes");
			return null;
		}
	}
	
	private static Layer parseLayer (JSONObject obj)	{
        try {
    		String nom = obj.getString("nom");		
    		//String desc = obj.has("desc")? obj.getString("desc") : "";
			Drawable icono = null;
    		if (obj.has("icono") && !obj.getString("icono").equals("")) {
    			try {
    				URL mUrl = new URL(obj.getString("icono"));
    				icono = Drawable.createFromStream(mUrl.openStream(), "src");
    			} catch (Exception e) { 
    				Log.e("parseLayer","Error al llegir l'icono");
					return null;
				}
    		}
    		int id = obj.optInt("id",0);
    		JSONArray array = obj.getJSONArray("nodes");
    		Layer l = new Layer(id,nom,icono); // IDs = 0 perque IDs negatius indiquen que son headers
			if (obj.has("checked")) l.visible = (obj.getBoolean("checked"));
			 
			for (int i = 0; i < array.length(); i++) { 
				Punt node = parseNode (array.getJSONObject(i));
				if (node != null) {
					node.setLayer(l);
					l.nodes.add(node);
				}
			}
			Log.i("ParseLayerList", "Llegits " + l.nodes.size() + " nodes.");
			if (l.nodes.size() == 0) {
				Log.i("ParseLayerList", "Capa buida");
				return null;
			}
			
			return l;
		} catch (JSONException e) {	
			Log.e("ParseNodes","Format de capa incorrecte");
			Log.e("ParseNodes",e.getMessage());
			//Si l'error es que no troba "nom" es que hi ha punts sense tipus.
			return null;
		}
	}
	
	private static Punt parseNode(JSONObject obj) {
		try {
			String description = (obj.has("desc"))? obj.getString("desc") : null;
			String name = (obj.has("nom")) ? obj.getString("nom") : null;
			int type = (obj.has("type")) ? obj.getInt("type") : 0;
			String photo_url = (obj.has("photo_url")) ? obj.getString("photo_url") : null;
			String info_url = (obj.has("url"))? obj.getString("url") : null;
			int id = (obj.has("id"))? obj.getInt("id") : 0;
			Double lat = (obj.has("lat"))? obj.getDouble("lat") : 0.0;
			Double lng = (obj.has("lng"))? obj.getDouble("lng") : 0.0;
			Double z = (obj.has("z"))? obj.getDouble("z") : 0.0;
			Punt myPhoto = new Punt(id, lat, lng, z, name,description,type);
			myPhoto.setPhotoUrl(photo_url);
			myPhoto.setUrlInfo(info_url);
			
			return myPhoto;
			
		} catch (JSONException e) {	
			Log.e("ParseNode","Parse error: "+e.getMessage());
			return null;
		}
	}

}
